home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / Snippets / Interapplication Communication / AE Interaction Sample / sender.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-07  |  19.4 KB  |  540 lines  |  [TEXT/MPS ]

  1. /* Sender and Reciever are simple AppleEvent programs that demonstrate */
  2. /* all the permutations of interaction levels for sending */
  3. /* and recieving APpleEvents. */
  4. /* Have fun with them. */
  5. /*  P.S. This also uses PBCatSearch, so I've done the typing for you if you've wanted */
  6. /* to use this call but have been confused by the param block */
  7. /* C.K. Haun */
  8. /* Apple DTS */
  9. /* this sends the simple event */
  10.  
  11.  
  12. #include <Types.h>
  13. #include <memory.h>
  14. #include <Packages.h>
  15. #include <Errors.h>
  16. #include <quickdraw.h>
  17. #include <fonts.h>
  18. #include <dialogs.h>
  19. #include <windows.h>
  20. #include <menus.h>
  21. #include <events.h>
  22. #include <OSEvents.h>
  23. #include <Desk.h>
  24. #include <diskinit.h>
  25. #include <OSUtils.h>
  26. #include <resources.h>
  27. #include <toolutils.h>
  28. #include <AppleEvents.h>
  29. #include <EPPC.h>
  30. #include <GestaltEqu.h>
  31. #include <PPCToolbox.h> 
  32. #include <Processes.h>
  33. /* prototypes */
  34. void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
  35. void DrawMain(WindowPtr drawIt);
  36. Boolean DoSelected(long val);
  37. pascal Boolean idleProc(EventRecord *eventIn, long *sleep, RgnHandle *mouseRgn);
  38. void InitAEStuff(void);
  39. void DoHighLevel(EventRecord *AERecord);
  40. void DoDaCall(MenuHandle themenu, long theit);
  41.      OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  42.      OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  43.      OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  44.      OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  45.      OSErr AEReplyHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  46. void SendSimple(void);
  47. OSErr FindReciever(AEDesc *theAddress);
  48. #define kSwitchItem 5
  49. #define kReplyItem 7
  50. short gSendInteractArray[4] = 
  51. {
  52.     nil, kAENeverInteract, kAECanInteract, kAEAlwaysInteract, 
  53. };
  54.  
  55.  
  56.  
  57. short replyLevels[] = 
  58. {
  59.     kAENoReply, kAEWaitReply,kAEQueueReply
  60. };
  61.  
  62.  
  63. short replyValue = 0;
  64.  
  65. short gInteract = 1;
  66. short gSwitchLayer = false;
  67. LaunchParamBlockRec launchThis;
  68.  
  69. #define kMBarID 128
  70. #define kAppleMenu 128
  71. #define kFileMenu 129
  72. #define kEditMenu 130
  73. #define kToolsMenu 131
  74. #define kSendButton 128
  75. #define kResumeMask             1       /* bit of message field for resume vs. suspend */
  76. #define kBadCombo 129
  77. #define kNoFind 130
  78. #define kSearch 200
  79. MenuHandle gAppleMenuHandle, gFileMenuHandle, gEditMenuHandle, gToolMenuHandle;
  80. Handle gMymenu;                                             /* my menu bar handle */
  81. ControlHandle sendButton;
  82.  
  83. AEAddressDesc targetAddress;                                /* address of the person to get the data from */
  84.  
  85.  
  86. #ifdef powerc
  87.    QDGlobals    qd;
  88. #endif
  89.  
  90. #define kSimpleEvent 'SIMP'
  91. #define kSimpleClass 'Simp'
  92. Boolean gQuit, gInBackground;
  93. EventRecord gERecord;
  94. AEDesc gTheAddress;
  95. AEIdleUPP gAEIdleUPP;
  96. WindowPtr myWindow;
  97. main()
  98. {
  99.     WindowPtr twindow;
  100.     ControlHandle returnedControl;
  101.     MaxApplZone();
  102.     InitGraf((Ptr)&qd.thePort);
  103.     InitFonts();
  104.     InitWindows();
  105.     InitMenus();
  106.     TEInit();
  107.     InitDialogs(nil);
  108.     InitCursor();
  109.     
  110.     InitAEStuff();
  111.     /* set up my menu junk */
  112.     gMymenu = GetNewMBar(kMBarID);
  113.     SetMenuBar(gMymenu);
  114.     gAppleMenuHandle = GetMenuHandle(kAppleMenu);
  115.     gFileMenuHandle = GetMenuHandle(kFileMenu);
  116.     gEditMenuHandle = GetMenuHandle(kEditMenu);
  117.     gToolMenuHandle = GetMenuHandle(kToolsMenu);
  118.     CheckItem(gToolMenuHandle, gInteract, true);
  119.     CheckItem(gToolMenuHandle, replyValue+kReplyItem, true);
  120.     AppendResMenu(gAppleMenuHandle, 'DRVR');
  121.  
  122.     
  123.    
  124.     /* this finds and launches the receiver */
  125.     if(FindReciever(&gTheAddress) != noErr){
  126.         StopAlert(kNoFind,nil);
  127.         ExitToShell();}
  128.     DrawMenuBar();
  129.     myWindow = GetNewWindow(128, nil, (WindowPtr)-1);
  130.     GetNewControl(kSendButton, myWindow);
  131.     do {
  132.         WaitNextEvent(everyEvent, &gERecord, 30, nil);
  133.         switch (gERecord.what) {
  134.             
  135.             case nullEvent:
  136.                 /* no nul processing in this sample */
  137.                 break;
  138.             case updateEvt:
  139.                 DrawMain((WindowPtr)gERecord.message);      /* draw whatever window needs an update */
  140.                 break;
  141.             case mouseDown:
  142.                 /* first see where the hit was */
  143.                 switch (FindWindow(gERecord.where, &twindow)) {
  144.                     
  145.                     case inDesk:                            /* if they hit in desk, then the process manager */
  146.                         break;                              /* will switch us out, we don't need to do anything */
  147.                     case inMenuBar:
  148.                         DoSelected(MenuSelect(gERecord.where));
  149.                         break;
  150.                         
  151.                     case inSysWindow:
  152.                         /* pass to the system */
  153.                         SystemClick(&gERecord, twindow);
  154.                         break;
  155.                     case inContent:
  156.                         GlobalToLocal(&gERecord.where);
  157.                         /* track my button as needed */
  158.                         if (FindControl(gERecord.where, twindow, &returnedControl)) {
  159.                             if (TrackControl(returnedControl, gERecord.where, nil)) {
  160.                                 SendSimple();
  161.                             }
  162.                         }
  163.                         break;
  164.                     case inDrag:
  165.                         if (twindow == FrontWindow())
  166.                             DragWindow(twindow, gERecord.where, &qd.screenBits.bounds);
  167.                         break;
  168.                     case inGrow:
  169.                     case inGoAway:
  170.                         /* don't care */
  171.                         break;
  172.                         
  173.                 }
  174.             case mouseUp:
  175.                 /* don't care */
  176.                 break;
  177.                 /* same action for key or auto key */
  178.             case keyDown:
  179.             case autoKey:
  180.                 if (gERecord.modifiers & cmdKey)
  181.                     DoSelected(MenuKey(gERecord.message & charCodeMask));
  182.                 break;
  183.             case keyUp:
  184.                 /* don't care */
  185.                 break;
  186.             case diskEvt:
  187.                 /* I don't do anything special for disk events, this just passes them */
  188.                 /* to a function that checks for an error on the mount */
  189.                 DoDiskEvents(gERecord.message);
  190.                 break;
  191.             case activateEvt:
  192.                 if (gERecord.modifiers & activeFlag)
  193.                     DrawMain((WindowPtr)gERecord.message);
  194.                 break;
  195.             case networkEvt:
  196.                 /* don't care */
  197.                 break;
  198.             case driverEvt:
  199.                 /* don't care */
  200.                 break;
  201.             case app4Evt:
  202.                 switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
  203.                     case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
  204.                         gInBackground = (gERecord.message & kResumeMask) == 0;
  205.                         break;
  206.                 }
  207.                 break;
  208.             default:
  209.                 break;
  210.                 /* This dispatches high level events (AppleEvents, for example) */
  211.                 /* to our dispatch routine.  This is NEW in the event loop for */
  212.                 /* System 7 */
  213.             case kHighLevelEvent:
  214.                 DoHighLevel(&gERecord);
  215.                 break;
  216.                 
  217.         }
  218.     } while (gQuit != true);
  219.     
  220.     
  221. }
  222.  
  223. /* DoDaCall opens the requested DA.  It's here as a seperate routine if you'd */
  224. /* like to perform some action or just know when a DA is opened in your */
  225. /* layer.  Can be handy to track memory problems when a DA is opened */
  226. /* with an Option-open */
  227. void DoDaCall(MenuHandle themenu, long theit)
  228. {
  229.     long qq;
  230.     char DAname[255];
  231.     GetMenuItemText(themenu, theit, &DAname);
  232.     qq = OpenDeskAcc(DAname);
  233. }
  234.  
  235. /* end DoDaCall */
  236.  
  237. /* DoDiskEvents just checks the error code from the disk mount, */
  238. /* and puts up the 'Format' dialog (through DIBadMount) if need be */
  239. /* You can do much more here if you care about what disks are */
  240. /* in the drive */
  241. void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
  242. {
  243.     short hival, loval, tommy;
  244.     Point fredpoint =  {
  245.         40, 40
  246.     };
  247.     hival = HiWord(dinfo);
  248.     loval = LoWord(dinfo);
  249.     if (hival != noErr)                                     /* something happened */ {
  250.         tommy = DIBadMount(fredpoint, dinfo);
  251.     }
  252. }
  253.  
  254. /* draws my window.  Pretty simple */
  255. void DrawMain(WindowPtr drawIt)
  256. {
  257.     BeginUpdate(drawIt);
  258.     SetPort(drawIt);
  259.     DrawControls(drawIt);
  260.     EndUpdate(drawIt);
  261. }
  262.  
  263. /* my menu action taker.  It returns a Boolean which I usually ignore, but it */
  264. /* mught be handy someday */
  265. Boolean DoSelected(long val)
  266. {
  267.     short loval, hival;
  268.     Boolean temp = false;
  269.     loval = LoWord(val);
  270.     hival = HiWord(val);
  271.     
  272.     switch (hival) {                                        /* switch off the menu number selected */
  273.         case kAppleMenu:                                    /* Apple menu */
  274.             if (loval != 1) {                               /* if this was not About, it's a DA */
  275.                 DoDaCall(gAppleMenuHandle, loval);
  276.             } else {
  277.                 Alert(128, nil);                            /* do about box */
  278.             }
  279.             break;
  280.         case kFileMenu:                                     /* File menu */
  281.             gQuit = true;                                   /* only  item */
  282.             break;
  283.         case kEditMenu:
  284.             /* edit menu junk */
  285.             /* don't care */
  286.             break;
  287.             /* This is the interaction level menu, sets checks and variables */
  288.         case kToolsMenu:
  289.             if (loval == kSwitchItem) {
  290.                if (gSwitchLayer) gSwitchLayer = false;
  291.                  else gSwitchLayer = kAECanSwitchLayer;
  292.  
  293.                 CheckItem(gToolMenuHandle, kSwitchItem, gSwitchLayer);
  294.             } else {
  295.                 if (loval >= kReplyItem) {
  296.                     if(loval != replyValue){
  297.                     
  298.                     CheckItem(gToolMenuHandle, replyValue+kReplyItem, false);
  299.                     CheckItem(gToolMenuHandle,loval,true);
  300.                     replyValue = loval - kReplyItem;}
  301.                 } else {
  302.                     if (gInteract != loval) {
  303.                         CheckItem(gToolMenuHandle, gInteract, false);
  304.                         CheckItem(gToolMenuHandle, loval, true);
  305.                         gInteract = loval;
  306.                     }
  307.                 }
  308.             }
  309.             break;
  310.     }
  311.     HiliteMenu(0);
  312. }
  313.  
  314. /* InitAEStuff installs my appleevent handlers */
  315. void InitAEStuff(void)
  316. {    
  317.     OSErr aevtErr = noErr;
  318.     long aLong = 0;
  319.     Boolean gHasAppleEvents = false;
  320.     /* Check this machine for AppleEvents.  If they are not here (ie not 7.0)
  321.     *   then we exit */
  322.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
  323.     /* The following series of calls installs all our AppleEvent Handlers.
  324.     *   These handlers are added to the application event handler list that 
  325.     *   the AppleEvent manager maintains.  So, whenever an AppleEvent happens
  326.     *   and we call AEProcessEvent, the AppleEvent manager will check our
  327.     *   list of handlers and dispatch to it if there is one.
  328.     */
  329.     if (gHasAppleEvents) {
  330.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, 
  331.              NewAEEventHandlerProc(AEOpenHandler),0, false);
  332.              if (aevtErr)  ExitToShell();
  333.  
  334.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, 
  335.              NewAEEventHandlerProc(AEOpenDocHandler),0, false);
  336.              if (aevtErr)  ExitToShell();
  337.  
  338.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
  339.              NewAEEventHandlerProc(AEQuitHandler), 0, false);
  340.              if (aevtErr)  ExitToShell();
  341.  
  342.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, 
  343.              NewAEEventHandlerProc(AEPrintHandler),0, false);
  344.              if (aevtErr)  ExitToShell();
  345.  
  346.          aevtErr = AEInstallEventHandler(kCoreEventClass, kAEAnswer, 
  347.              NewAEEventHandlerProc(AEReplyHandler),0, false);
  348.              if (aevtErr)  ExitToShell();
  349.  
  350.          if (aevtErr)  ExitToShell();
  351.          
  352.          /* create a UPP for the AppleEvent idle proc */
  353.          gAEIdleUPP = NewAEIdleProc(idleProc);
  354.  
  355.        } 
  356.     else ExitToShell();
  357.     
  358. }
  359. /* end InitAEStuff */
  360.  
  361.  
  362. /* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
  363. /* easy for me to say, huh? */
  364. void DoHighLevel(EventRecord *AERecord)
  365. {
  366.     
  367.     AEProcessAppleEvent(AERecord);
  368.     
  369. }
  370.  
  371. /* end DoHighLevel */
  372.  
  373. /* This is the standard Open Application event.  */
  374.      OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  375. {
  376. #pragma unused (messagein,reply,refIn)
  377.     /* we of course don't do anything here in this simple app */
  378.     return(noErr);
  379. }
  380.  
  381. /* end AEOpenHandler */
  382.  
  383. /* Open Doc, opens our documents.  Remember, this can happen at application start AND */
  384. /* anytime else.  If your app is up and running and the user goes to the desktop, hilites one */
  385. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  386. /* handler will get called. Which means you don't do any initialization of globals here, or */
  387. /* anything else except open then doc.  */
  388. /* SO-- Do NOT assume that you are at app start time in this */
  389. /* routine, or bad things will surely happen to you. */
  390.  
  391.      OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  392. {
  393. #pragma unused (reply, refIn)
  394.     /* we of course don't do anything here */
  395.     return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
  396. }
  397.  
  398.      OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  399. {                                                           /* no printing handler in yet, so we'll ignore this */
  400.     /* the operation is functionally identical to the ODOC event, with the additon */
  401.     /* of calling your print routine.  */
  402. #pragma unused (reply,refIn)
  403.     /* we of course don't do anything here */
  404.     return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
  405. }
  406.  
  407. /* Standard Quit event handler, to handle a Quit event from the Finder, for example.  */
  408. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life.  */
  409.      OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  410. {
  411. #pragma unused (messagein,refIn)
  412.     
  413.     /* prepQuit sets the Stop flag for us.  It does _NOT_ quit, you */
  414.     /* should NEVER quit from an AppleEvent handler.  Calling */
  415.     /* ExitToShell here would blow things up */
  416.     gQuit = true;
  417.     return(noErr);
  418. }
  419. /* ReplyHandler is used when I've used QueueReply, which means that the */
  420. /* reply will come in through my event loop */
  421.      OSErr AEReplyHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  422. {
  423. #pragma unused (messagein,refIn)
  424. return(noErr);
  425. }
  426. /* SendSimple sends our simple event.  About simplest demo of an AESEnd */
  427. void SendSimple(void)
  428. {
  429.     AppleEvent ourEvent,ourReply;
  430.     short sendIt = 2;
  431.     AECreateAppleEvent(kSimpleClass, kSimpleEvent, &gTheAddress, kAutoGenerateReturnID, kAnyTransactionID, &ourEvent);
  432.     if (replyLevels[replyValue] == kAEWaitReply && !gSwitchLayer) {
  433.         sendIt = StopAlert(kBadCombo, nil);
  434.     }
  435.     if (sendIt == 2) {
  436.         AESend(&ourEvent, &ourReply, (gSendInteractArray[gInteract] + gSwitchLayer) + replyLevels[replyValue], kAENormalPriority,
  437.                kAEDefaultTimeout,gAEIdleUPP, nil);
  438.     }
  439.     AEDisposeDesc(&ourEvent);
  440.     if(replyLevels[replyValue] == kAEWaitReply)AEDisposeDesc(&ourReply);
  441. }
  442.  
  443. /* I'm just launching it, not searching for a port */
  444. /* I use PBCatSearch to search for it's creator and file type. */
  445. OSErr FindReciever(AEDesc *theAddress)
  446. {
  447.     OSErr myError;
  448.     DialogPtr search = GetNewDialog(kSearch,nil,(WindowPtr)-1);
  449.     CSParamPtr csBlockPtr = NewPtrClear(sizeof(CSParam));
  450.     long dirIDUnused;
  451.     Str32 nulString = "\p";
  452.     /* initialize the parameter block */
  453.     DrawDialog(search);
  454.     if (csBlockPtr) {
  455.         csBlockPtr->ioSearchInfo1 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  456.         csBlockPtr->ioSearchInfo2 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  457.         if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2) {
  458.             csBlockPtr->ioMatchPtr = (FSSpecPtr)NewPtrClear(sizeof(FSSpec) * 1);        /* only looking for 1 */
  459.             if (csBlockPtr->ioMatchPtr) {
  460.                 /* Now see if we can create an optimization buffer */
  461.                 csBlockPtr->ioOptBuffer = NewPtr(2048);
  462.                 if (csBlockPtr->ioOptBuffer)
  463.                     csBlockPtr->ioOptBufSize = 2048;
  464.                 else
  465.                     csBlockPtr->ioOptBufSize = 0;           /* no buffer, sorry */
  466.                 csBlockPtr->ioReqMatchCount = 1;
  467.                 csBlockPtr->ioSearchTime = 0;               /* no timeout */
  468.             }
  469.         }
  470.     }
  471.     HGetVol(nil, &csBlockPtr->ioVRefNum, &dirIDUnused);     /* get default volume for search */
  472.     csBlockPtr->ioSearchInfo1->hFileInfo.ioNamePtr = nil;
  473.     csBlockPtr->ioSearchInfo2->hFileInfo.ioNamePtr = nil;
  474.     csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdCreator = 'MuuB';
  475.     csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdType = 'APPL';
  476.     csBlockPtr->ioSearchBits = fsSBFlFndrInfo;
  477.     csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
  478.     csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
  479.     
  480.     myError = PBCatSearch(csBlockPtr, false);               /* search sync */
  481.     if (myError == noErr && csBlockPtr->ioActMatchCount != 0) {
  482.         /* we found it, so launch it */
  483.         
  484.         launchThis.launchBlockID = extendedBlock;
  485.         launchThis.launchEPBLength = extendedBlockLen;
  486.         launchThis.launchFileFlags = nil;
  487.         launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchDontSwitch;
  488.         launchThis.launchAppSpec = &csBlockPtr->ioMatchPtr[0];
  489.         myError = LaunchApplication(&launchThis);
  490.         if (myError == noErr) {
  491.             /* it launched fine.  we can use the PSN to make a target */
  492.             AECreateDesc(typeProcessSerialNumber, (Ptr)&launchThis.launchProcessSN, sizeof(ProcessSerialNumber), theAddress);
  493.             
  494.         }
  495.     }
  496.     
  497.     /* no matter what happened, kill the memory we had allocated */
  498.     if (csBlockPtr) {
  499.         if (csBlockPtr->ioSearchInfo1)
  500.             DisposePtr((Ptr)csBlockPtr->ioSearchInfo1);
  501.         if (csBlockPtr->ioSearchInfo2)
  502.             DisposePtr((Ptr)csBlockPtr->ioSearchInfo2);
  503.         if (csBlockPtr->ioMatchPtr)
  504.             DisposePtr((Ptr)csBlockPtr->ioMatchPtr);
  505.         if (csBlockPtr->ioOptBuffer)
  506.             DisposePtr((Ptr)csBlockPtr->ioOptBuffer);
  507.         DisposePtr((Ptr)csBlockPtr);
  508.     }
  509.     
  510.     /* catsearch section end */
  511.     DisposeDialog(search);
  512.     return(myError);
  513. }
  514. /* My IdleProc for AESend */
  515. pascal Boolean idleProc(EventRecord *eventIn, long *sleep, RgnHandle *mouseRgn)
  516. {
  517.     switch (eventIn->what) {
  518.         case nullEvent:
  519.             /* no nul processing in this sample */
  520.             *sleep = 0;
  521.             mouseRgn = nil;
  522.             break;
  523.         case updateEvt:
  524.         case activateEvt:
  525.             DrawMain((WindowPtr)eventIn->message);          /* draw whatever window needs an update */
  526.             break;
  527.         case app4Evt:
  528.             switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
  529.                 case suspendResumeMessage:                  /* suspend/resume is also an activate/deactivate */
  530.                     gInBackground = (gERecord.message & kResumeMask) == 0;
  531.                     break;
  532.             }
  533.             break;
  534.             
  535.             
  536.             
  537.     }
  538. return(false);    /* I'll wait forever */
  539. }
  540.